/*
 * Copyright Radosław Smogura, 2012. All rights reserved.
 *
 * The content of this file is confidential and it is intelectual property
 * of copyright owners.
 * 
 *
 * $URL: http://reprap-ide.googlecode.com/svn/trunk/RepRapIDE/RepRapProject/src/main/java/eu/softper/reprap/generator/AngleReducer.java $
 * $Id: AngleReducer.java 3 2012-11-19 10:58:30Z mail@smogura.eu $
 * $Revision: 3 $
 */
package eu.softper.reprap.generator;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Set;

/** If scene line has more then one angle reduce it to wining angle.
 *
 * Let's a_1, a_2 be scne line angles then |a_1 - a_2)| \in {0, 180}, 
 * with respect to floating point precision, so we take only angle which has
 * most same
 * 
 * @author rsmogura
 */
public class AngleReducer<T extends Number & Comparable<T>> {
    private final T DEG_360;
    private final T DEG_90;
    
    private Layer<T> layer;

    private NumericFactory<T> nf;
    
    public AngleReducer(NumericFactory<T> nf, Layer<T> layer) {
        this.layer = layer;
        this.nf = nf;
        
        DEG_360 = nf.valueOf(360);
        DEG_90 = nf.valueOf(90);
    }
    
    public void reduceAngles() {
        for (SceneLine<T> sl : layer.getOutlines()) {
            Set<T> angles = sl.getXyNormalsAngles();
            if (angles.size() < 2)
                continue;
            
            /* Calculate same and oposite angles to first angle. */
            
            int same = 1, oposite = 0; /* First angle is always same. */
            T opositeAngle = null;
            Iterator<T> i = angles.iterator();
            final T angle = i.next();
            while (i.hasNext()) {
                final T a = i.next();
                final T diff = nf.reminder(nf.abs(nf.subs(a, angle)), DEG_360);
                if (diff.compareTo(DEG_90) <= 0) {
                    same++;
                }else {
                    oposite++;
                    opositeAngle = a;
                }
            }
            
            /* If same is same as oposite, this means that line is as well 
            * opening and closing - remove it, otherwise take angle or negated
            * angle
            */
            sl.getXyNormalsAngles().clear();
            if (same == oposite) {
                /* Nothing to do list is cleared. */
            }else if (same < oposite) {
                sl.getXyNormalsAngles().add(opositeAngle);
            }else {
                sl.getXyNormalsAngles().add(angle);
            }
        }
    }
}
